# File: app/utils/exceptions.py

from fastapi import status


# ===================================================================
# 1. 自定义应用异常基类 (The Base Class)
# ===================================================================

class AppException(Exception):
    """
    应用的自定义异常基类。

    所有业务相关的、可预见的异常都应继承自此类。

    Attributes:
        status_code (int): 希望返回给客户端的 HTTP 状态码。
        code (int): 自定义的、更精细的业务错误码。
        message (str): 人类可读的、用于展示给用户的错误信息。
        data (any): 可选的、用于携带额外错误信息的载体。
    """

    def __init__(
            self,
            status_code: int,
            code: int,
            message: str,
            data: any = None
    ):
        self.status_code = status_code
        self.code = code
        self.message = message
        self.data = data
        super().__init__(message)


# ===================================================================
# 2. 具体业务异常 (Specific Business Exceptions)
# ===================================================================

# ------------------- 认证相关异常 (业务码 401xx) -------------------

class AuthenticationException(AppException):
    """认证异常基类"""

    def __init__(self, message: str = "认证失败", code: int = 40100):
        super().__init__(
            status_code=status.HTTP_401_UNAUTHORIZED,
            code=code,
            message=message
        )


class InvalidCredentialsException(AuthenticationException):
    """无效的凭证（用户名或密码错误）"""

    def __init__(self):
        super().__init__(message="无效的用户名或密码", code=40101)


class TokenExpiredException(AuthenticationException):
    """Token 已过期"""

    def __init__(self):
        super().__init__(message="Token 已过期", code=40102)


class TokenBlacklistedException(AuthenticationException):
    """Token 已被加入黑名单"""

    def __init__(self):
        super().__init__(message="Token 已被列入黑名单", code=40103)


class InvalidTokenException(AuthenticationException):
    """无效的 Token（格式错误、解析失败等）"""

    def __init__(self):
        super().__init__(message="无效的 Token", code=40104)


class UserInactiveException(AuthenticationException):
    """用户账户未激活或被禁用"""

    def __init__(self):
        super().__init__(message="用户账户未激活或已被禁用", code=40105)


# ------------------- 授权相关异常 (业务码 403xx) -------------------

class AuthorizationException(AppException):
    """授权异常（权限不足）"""

    def __init__(self, message: str = "权限不足", code: int = 40300):
        super().__init__(
            status_code=status.HTTP_403_FORBIDDEN,
            code=code,
            message=message,
        )


# ------------------- 资源未找到异常 (业务码 404xx) -----------------

class NotFoundException(AppException):
    """资源未找到异常基类"""

    def __init__(self, message: str = "资源未找到", code: int = 40400):
        super().__init__(
            status_code=status.HTTP_404_NOT_FOUND,
            code=code,
            message=message,
        )


class UserNotFoundException(NotFoundException):
    """用户未找到"""

    def __init__(self):
        super().__init__(message="用户未找到", code=40401)


# ------------------- 资源冲突异常 (业务码 409xx) -------------------

class ConflictException(AppException):
    """资源冲突或重复异常基类"""

    def __init__(self, message: str = "资源已存在", code: int = 40900):
        super().__init__(
            status_code=status.HTTP_409_CONFLICT,
            code=code,
            message=message,
        )


class UserAlreadyExistsException(ConflictException):
    """用户已存在"""

    def __init__(self, field: str = "用户"):
        # 允许动态地指定是哪个字段冲突
        super().__init__(message=f"该 {field} 已存在", code=40901)


# ------------------- 请求校验异常 (业务码 422xx) -------------------
# 注意：FastAPI 的 RequestValidationError 通常会自动处理请求体的校验。
# 这里的 ValidationException 更适用于业务逻辑层面的校验失败。

class ValidationException(AppException):
    """业务逻辑校验异常"""

    def __init__(self, message: str = "校验失败", code: int = 42200, data: any = None):
        super().__init__(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            code=code,
            message=message,
            data=data  # 这个 data 字段可以用来携带详细的字段错误信息
        )
